package co.fitstart.coach.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dynamic;

import co.fitstart.coach.dao.BasicInformationDao;
import co.fitstart.coach.dao.RecordDao;
import co.fitstart.coach.service.BasicInformationService;
import co.fitstart.entity.course.round.CourseRound;
import co.fitstart.entity.course.round.Goal;
import co.fitstart.entity.courseware.assessment.BasicData;
import co.fitstart.entity.courseware.assessment.Disease;
import co.fitstart.entity.courseware.assessment.PostureJoint;
import co.fitstart.entity.courseware.assessment.StudentAssessment;
import co.fitstart.entity.courseware.assessment.StudentHabit;
import co.fitstart.entity.user.basic.BodyDataTarget;
import co.fitstart.entity.user.basic.enums.BodyDataType;
import co.fitstart.entity.user.bwh.BwhRecord;

/**
 * 
 * @author haiyan_xiao
 *
 */
@Service("basicInformationService")
public class BasicInformationServiceImpl implements BasicInformationService {
    @Dynamic
    private RecordDao recordDao;
    
    @Dynamic
    private BasicInformationDao basicInformationDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#loadGoal(co.fitstart.entity.course.round.CourseRound)
     */
    public Goal loadGoal(CourseRound courseRound) {
        return genericDaoSupport.searchForObject("FROM Goal WHERE disabled = false"
                + " AND courseRound = :courseRound", "courseRound", courseRound, Goal.class);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#listBodyDataTarget(co.fitstart.entity.course.round.CourseRound)
     */
    @SuppressWarnings("unchecked")
    public List<BodyDataTarget> listBodyDataTarget(CourseRound courseRound) {
        return genericDaoSupport.searchForList("FROM BodyDataTarget WHERE disabled = false"
                + " AND courseRound = :courseRound", "courseRound", courseRound);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#listBwhRecord(co.fitstart.entity.course.round.CourseRound)
     */
    public Map<Integer, BwhRecord> listBwhRecord(CourseRound courseRound) {
        List<BwhRecord> bwhRecords = recordDao.listBwhRecord(courseRound);
        
        Map<Integer, BwhRecord> result = new HashMap<>();
        
        if(!bwhRecords.isEmpty()) {
            for(BwhRecord bwhRecord : bwhRecords) {
                result.put(bwhRecord.getWeek(), bwhRecord);
            }
        }
        
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editTarget(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.course.round.Goal, java.util.List, java.util.List)
     */
    public void editTarget(CourseRound courseRound, Goal goal, List<BodyDataTarget> bodyDataTargets, List<BwhRecord> bwhRecords) {
        // 1. edit Goal
        Goal originalGoal = this.loadGoal(courseRound);
        if(originalGoal == null) {
            if(StringUtils.isNotBlank(goal.getReachTime()) || StringUtils.isNotBlank(goal.getContent())) {
                Goal newGoal = new Goal(courseRound);
                genericDaoSupport.save(newGoal.edit(goal.getReachTime(), goal.getContent()));
            }
        } else {
            genericDaoSupport.update(originalGoal.edit(goal.getReachTime(), goal.getContent()));
        }
        
        // 2. edit body data target
        for(BodyDataTarget bodyDataTarget : bodyDataTargets) {
            BodyDataTarget originalBodyDataTarget = this.loadBodyDataTarget(courseRound, bodyDataTarget.getBodyDataType());
            
            if(originalBodyDataTarget == null) {
                if(bodyDataTarget.getCurrentValue() != null || bodyDataTarget.getCoachIdealValue() != null || bodyDataTarget.getIdealValue() != null) {
                    BodyDataTarget newBodyDataTarget = new BodyDataTarget(courseRound, bodyDataTarget.getBodyDataType());
                    
                    genericDaoSupport.save(newBodyDataTarget.edit(bodyDataTarget.getCurrentValue(),
                            bodyDataTarget.getIdealValue(), bodyDataTarget.getCoachIdealValue()));
                }
            } else {
                genericDaoSupport.update(originalBodyDataTarget.edit(bodyDataTarget.getCurrentValue(),
                        bodyDataTarget.getIdealValue(), bodyDataTarget.getCoachIdealValue()));
            }
        }
        
        // 3. edit bwhRecord
        for(BwhRecord bwhRecord : bwhRecords) {
            BwhRecord originalBwhRecord = this.loadBwhRecord(courseRound, bwhRecord.getWeek());
            
            if(originalBwhRecord == null) {
                if(bwhRecord.getWeight() != null || bwhRecord.getBodyFatRate() != null || bwhRecord.getSkeletalMuscle() != null
                        || bwhRecord.getBust() != null || bwhRecord.getArm() != null || bwhRecord.getWaist() != null
                        || bwhRecord.getHips() != null || bwhRecord.getThigh() != null) {
                    BwhRecord newBwhRecord = new BwhRecord(courseRound, bwhRecord.getWeek());
                    
                    genericDaoSupport.save(newBwhRecord.edit(bwhRecord.getWeight(), bwhRecord.getBodyFatRate(),
                            bwhRecord.getSkeletalMuscle(), bwhRecord.getBust(), bwhRecord.getArm(),
                            bwhRecord.getWaist(), bwhRecord.getHips(), bwhRecord.getThigh(), courseRound.getCoach().getId()));
                }
            } else {
                genericDaoSupport.update(originalBwhRecord.edit(bwhRecord.getWeight(), bwhRecord.getBodyFatRate(),
                        bwhRecord.getSkeletalMuscle(), bwhRecord.getBust(), bwhRecord.getArm(),
                        bwhRecord.getWaist(), bwhRecord.getHips(), bwhRecord.getThigh(), courseRound.getCoach().getId()));
            }
        }
    }
    
    /**
     * 
     * @param courseRound
     * @param bodyDataType
     * @return
     */
    private BodyDataTarget loadBodyDataTarget(CourseRound courseRound, BodyDataType bodyDataType) {
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("courseRound", courseRound);
        parameters.put("bodyDataType", bodyDataType);
        
        return genericDaoSupport.searchForObject("FROM BodyDataTarget WHERE disabled = false AND courseRound = :courseRound AND bodyDataType = :bodyDataType", parameters, BodyDataTarget.class);
    }
    
    /**
     * 
     * @param courseRound
     * @param week
     * @return
     */
    private BwhRecord loadBwhRecord(CourseRound courseRound, int week) {
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("courseRound", courseRound);
        parameters.put("week", week);
        
        return genericDaoSupport.searchForObject("FROM BwhRecord WHERE disabled = false AND courseRound = :courseRound AND week = :week", parameters, BwhRecord.class);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#loadStudentAssessment(co.fitstart.entity.course.round.CourseRound)
     */
    public StudentAssessment loadStudentAssessment(CourseRound courseRound) {
        return basicInformationDao.loadStudentAssessment(courseRound);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#loadBasicData(co.fitstart.entity.course.round.CourseRound)
     */
    public BasicData loadBasicData(CourseRound courseRound) {
        return genericDaoSupport.searchForObject("FROM BasicData WHERE disabled = false"
                + " AND courseRound = :courseRound", "courseRound", courseRound, BasicData.class);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#loadStudentHabit(co.fitstart.entity.course.round.CourseRound)
     */
    public StudentHabit loadStudentHabit(CourseRound courseRound) {
        return genericDaoSupport.searchForObject("FROM StudentHabit WHERE disabled = false"
                + " AND courseRound = :courseRound", "courseRound", courseRound, StudentHabit.class);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#loadPostureJoint(co.fitstart.entity.course.round.CourseRound)
     */
    public PostureJoint loadPostureJoint(CourseRound courseRound) {
        return genericDaoSupport.searchForObject("FROM PostureJoint WHERE disabled = false"
                + " AND courseRound = :courseRound", "courseRound", courseRound, PostureJoint.class);
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editStudentAssessment(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.courseware.assessment.BasicData, java.util.List, co.fitstart.entity.courseware.assessment.PostureJoint)
     */
    public void editStudentAssessment(CourseRound courseRound, BasicData basicData, List<Disease> diseases,
            PostureJoint postureJoint) {
        // create basicData
        genericDaoSupport.save(basicData.initialize(courseRound).editDisease(diseases));
        
        // create postureJoint
        genericDaoSupport.save(postureJoint.initialize(courseRound));
        
        // create studentAssessment
        StudentAssessment studentAssessment = new StudentAssessment(courseRound, basicData, postureJoint);
        genericDaoSupport.save(studentAssessment);
        
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editBasicData(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.courseware.assessment.BasicData, java.util.List)
     */
    public void editBasicData(CourseRound courseRound, BasicData basicData, List<Disease> diseases) {
        BasicData originalBasicData = this.loadBasicData(courseRound);
        
        if(originalBasicData == null) {
            genericDaoSupport.save(basicData.initialize(courseRound).editDisease(diseases));
        } else {
            genericDaoSupport.update(originalBasicData.edit(basicData).editDisease(diseases));
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editStudentHabit(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.user.basic.StudentHabit)
     */
    public void editStudentHabit(CourseRound courseRound, StudentHabit studentHabit) {
        StudentHabit originalHabit = this.loadStudentHabit(courseRound);
        
        if(originalHabit == null) {
            genericDaoSupport.save(studentHabit.initialize(courseRound));
        } else {
            genericDaoSupport.update(originalHabit.edit(studentHabit));
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editPostureJoint(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.courseware.assessment.PostureJoint)
     */
    public void editPostureJoint(CourseRound courseRound, PostureJoint postureJoint) {
        PostureJoint originalPostureJoint = this.loadPostureJoint(courseRound);
        
        if(originalPostureJoint == null) {
            genericDaoSupport.save(postureJoint.initialize(courseRound));
        } else {
            genericDaoSupport.update(originalPostureJoint.edit(postureJoint));
        }
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editJointFlexibility(co.fitstart.entity.course.round.CourseRound, java.lang.String, java.lang.String, java.lang.String)
     */
    public void editJointFlexibility(CourseRound courseRound, String postureSummary, String jointSummary, String summary) {
        PostureJoint postureJoint = this.loadPostureJoint(courseRound);
        
        if(postureJoint == null) {
            PostureJoint newPostureJoint = new PostureJoint(courseRound);
            genericDaoSupport.save(newPostureJoint.edit(postureSummary, jointSummary, summary));
        } else {
            genericDaoSupport.update(postureJoint.edit(postureSummary, jointSummary, summary));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editGetUpTime(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editGetUpTime(CourseRound courseRound, String getUpTime) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editGetUpTime(getUpTime));
        } else {
            genericDaoSupport.update(habit.editGetUpTime(getUpTime));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editSleepTime(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editSleepTime(CourseRound courseRound, String sleepTime) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editSleepTime(sleepTime));
        } else {
            genericDaoSupport.update(habit.editSleepTime(sleepTime));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editEntertainmentFrequency(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editEntertainmentFrequency(CourseRound courseRound, String entertainmentFrequency) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editEntertainmentFrequency(entertainmentFrequency));
        } else {
            genericDaoSupport.update(habit.editEntertainmentFrequency(entertainmentFrequency));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editBreakfastTime(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editBreakfastTime(CourseRound courseRound, String breakfastTime) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editBreakfastTime(breakfastTime));
        } else {
            genericDaoSupport.update(habit.editBreakfastTime(breakfastTime));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editBreakfastType(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editBreakfastType(CourseRound courseRound, String breakfastType) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editBreakfastType(breakfastType));
        } else {
            genericDaoSupport.update(habit.editBreakfastType(breakfastType));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editBreakfastIntake(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editBreakfastIntake(CourseRound courseRound, String breakfastIntake) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editBreakfastIntake(breakfastIntake));
        } else {
            genericDaoSupport.update(habit.editBreakfastIntake(breakfastIntake));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editLunchTime(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editLunchTime(CourseRound courseRound, String lunchTime) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editLunchTime(lunchTime));
        } else {
            genericDaoSupport.update(habit.editLunchTime(lunchTime));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editLunchType(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editLunchType(CourseRound courseRound, String lunchType) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editLunchType(lunchType));
        } else {
            genericDaoSupport.update(habit.editLunchType(lunchType));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editLunchIntake(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editLunchIntake(CourseRound courseRound, String lunchIntake) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editLunchIntake(lunchIntake));
        } else {
            genericDaoSupport.update(habit.editLunchIntake(lunchIntake));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editDinnerTime(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editDinnerTime(CourseRound courseRound, String dinnerTime) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editDinnerTime(dinnerTime));
        } else {
            genericDaoSupport.update(habit.editDinnerTime(dinnerTime));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editDinnerType(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editDinnerType(CourseRound courseRound, String dinnerType) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editDinnerType(dinnerType));
        } else {
            genericDaoSupport.update(habit.editDinnerType(dinnerType));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editDinnerIntake(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editDinnerIntake(CourseRound courseRound, String dinnerIntake) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editDinnerIntake(dinnerIntake));
        } else {
            genericDaoSupport.update(habit.editDinnerIntake(dinnerIntake));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editSnackTime(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editSnackTime(CourseRound courseRound, String snackTime) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editSnackTime(snackTime));
        } else {
            genericDaoSupport.update(habit.editSnackTime(snackTime));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editSnackType(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editSnackType(CourseRound courseRound, String snackType) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editSnackType(snackType));
        } else {
            genericDaoSupport.update(habit.editSnackType(snackType));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editSnackIntake(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editSnackIntake(CourseRound courseRound, String snackIntake) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editSnackIntake(snackIntake));
        } else {
            genericDaoSupport.update(habit.editSnackIntake(snackIntake));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editWaterIntake(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editWaterIntake(CourseRound courseRound, String waterIntake) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editWaterIntake(waterIntake));
        } else {
            genericDaoSupport.update(habit.editWaterIntake(waterIntake));
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.coach.service.BasicInformationService#editHabitRemark(co.fitstart.entity.course.round.CourseRound, java.lang.String)
     */
    public void editHabitRemark(CourseRound courseRound, String remark) {
        StudentHabit habit = this.loadStudentHabit(courseRound);
        
        if(habit == null) {
            habit = new StudentHabit(courseRound);
            
            genericDaoSupport.save(habit.editRemark(remark));
        } else {
            genericDaoSupport.update(habit.editRemark(remark));
        }
    }

}
